Skip to content

GPU-accelerated SEACells (opt-in, end-to-end on GPU) - #83

Merged
sitarapersad merged 1 commit into
dpeerlab:mainfrom
hussenmi:gpu-acceleration
Aug 24, 2026
Merged

GPU-accelerated SEACells (opt-in, end-to-end on GPU)#83
sitarapersad merged 1 commit into
dpeerlab:mainfrom
hussenmi:gpu-acceleration

Conversation

@hussenmi

@hussenmi hussenmi commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

This adds a GPU version of SEACells. It's off by default; turn it on with use_gpu=True, use_unified=True and nothing else changes:

model = SEACells.core.SEACells(ad, build_kernel_on="X_pca", n_SEACells=90,
                               use_gpu=True, use_unified=True)

What's different on the GPU

The kernel stays on the GPU. The old GPU code kept the kernel on the CPU, copied it to the GPU every iteration, and computed the reconstruction error on the CPU. Keeping everything on the GPU makes each iteration about 18x faster. cd34 finishes in 6.5s instead of 110s.

The error avoids the big n×n matrix. The error used to be computed by building an n×n matrix, which gets huge at scale (174 GB for 200k cells). It's now computed with the identity ||M - MBA||^2 = ||M||^2 - 2 tr(KBA) + tr(B^T K B A A^T), which only needs n×s memory (about 10 GB for 200k cells). Same number, far less memory, so it runs on a single GPU at sizes the old code couldn't.

Same results

The GPU path gives the same answer as the CPU path (see tests/test_unified_parity.py), and on cd34 the CPU and GPU runs converge to the same error.

Install

uv sync for CPU, or uv sync --extra gpu for the GPU version (installs RAPIDS, CuPy, FAISS). Details in docs/gpu_speed_and_scale.md.

@hussenmi
hussenmi marked this pull request as ready for review August 20, 2026 19:18
Adds a unified SEACellsModel that runs the metacell solver on the GPU (kernel
build, Frank-Wolfe updates, and the objective) via two changes:

- K residency: keep the kernel resident on the GPU instead of re-uploading it
  and evaluating the reconstruction error on the CPU. ~18x faster per iteration
  at 15k cells; cd34 end-to-end 110s -> 6.5s (~17x).
- Reduced-form RSS: evaluate ||M - MBA|| via
  ||M||^2 - 2 tr(KBA) + tr(B^T K B  A A^T), with K = M^T M, which needs O(n*s)
  memory instead of the dense n x n reconstruction. Fits on one GPU at 200k+
  cells (~10 GB vs ~174 GB). Exact, not an approximation.

Opt-in via core.SEACells(use_gpu=True, use_unified=True); use_unified defaults to
False, so the existing CPU and legacy backends are unchanged. Adds parity tests
(unified CPU == legacy cpu_dense; reduced-form RSS == direct Frobenius norm;
GPU == CPU on a shared kernel). Same optimum: on cd34, CPU and GPU converge to
the same RSS.

Packaging via uv: `uv sync` (CPU) / `uv sync --extra gpu` (RAPIDS/CuPy/FAISS).
uv.lock is gitignored rather than committed. See docs/gpu_speed_and_scale.md.
@sitarapersad
sitarapersad merged commit a1173c8 into dpeerlab:main Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants